using Joy.Erp.BasicArchives.Core;
using Joy.Erp.BasicArchives.Core.Filters;
using Joy.Erp.BasicArchives.Permissions;
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories;

namespace Joy.Erp.BasicArchives.ItemMasters
{
    [Authorize]
    public class BomMasterAppService : BasicArchivesAppService, IBomMasterAppService
    {
        protected IBomMasterRepository BomMasterRepository => LazyServiceProvider.LazyGetRequiredService<IBomMasterRepository>();
        protected BomMasterManager BomMasterManager => LazyServiceProvider.LazyGetRequiredService<BomMasterManager>();

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<BomMasterDto> GetAsync(Guid id)
        {
            var entity = await BomMasterRepository.GetAsync(id, true);
            return ObjectMapper.Map<BomMaster, BomMasterDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<BomComponentDto> GetChildAsync(Guid id)
        {
            var child = await BomMasterRepository.GetChildAsync(id, true);
            return ObjectMapper.Map<BomComponent, BomComponentDto>(child);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<BomMasterDto> FindAsync(string filter)
        {
            var entity = await BomMasterRepository.FindAsync(x => x.Code == filter);
            return ObjectMapper.Map<BomMaster, BomMasterDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<BomMasterDto> FindBySourceKeyAsync(string sourceKey, string sourceType)
        {
            var entity = await BomMasterRepository.FindAsync(x => x.SourceKey == sourceKey && x.SourceType == sourceType);
            return ObjectMapper.Map<BomMaster, BomMasterDto>(entity);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<PagedResultDto<BomMasterDto>> GetListAsync(FilterRequestDto input)
        {
            var totalCount = await BomMasterRepository.GetCountAsync(input.Filter, true);
            var list = await BomMasterRepository.GetPagedListAsync(input.Filter, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<BomMasterDto>(
                totalCount,
                ObjectMapper.Map<List<BomMaster>, List<BomMasterDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<PagedResultDto<BomMasterDto>> QueryAsync(FilterGroupRequestDto input)
        {
            Expression<Func<BomMaster, bool>> expression = null;
            if (input != null && input.FilterGroup != null)
            {
                expression = FilterConverter.Convert<BomMaster>(input.FilterGroup);
            }

            var totalCount = await BomMasterRepository.GetCountAsync(expression, true);
            var list = await BomMasterRepository.GetPagedListAsync(expression, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<BomMasterDto>(
                totalCount,
                ObjectMapper.Map<List<BomMaster>, List<BomMasterDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<PagedResultDto<BomComponentDto>> QueryChildrenAsync(FilterGroupRequestDto input)
        {
            Expression<Func<BomComponent, bool>> expression = null;
            if (input != null && input.FilterGroup != null)
            {
                expression = FilterConverter.Convert<BomComponent>(input.FilterGroup);
            }

            var totalCount = await BomMasterRepository.GetChildrenCountAsync(expression, true);
            var list = await BomMasterRepository.GetChildrenPagedListAsync(expression, input.SkipCount, input.MaxResultCount, input.Sorting, true);

            return new PagedResultDto<BomComponentDto>(
                totalCount,
                ObjectMapper.Map<List<BomComponent>, List<BomComponentDto>>(list));
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Create)]
        public async Task<BomMasterDto> CreateAsync(BomMasterCreateDto input)
        {
            var entity = ObjectMapper.Map<BomMasterCreateDto, BomMaster>(input);

            await BomMasterManager.CreateAsync(entity, true);
            return await GetAsync(entity.Id);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Update)]
        public async Task<BomMasterDto> UpdateAsync(Guid id, BomMasterUpdateDto input)
        {
            var entity = await BomMasterRepository.GetAsync(id, true);
            entity.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);

            await BomMasterRepository.EnsureCollectionLoadedAsync(entity, x => x.Children);
            ObjectMapper.Map(input, entity);

            await BomMasterManager.UpdateAsync(entity, true);
            return await GetAsync(entity.Id);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Submit)]
        public async Task<BomMasterDto> SubmitAsync(Guid id)
        {
            await BomMasterManager.ChangeStatus(id, DocumentStatus.Waiting);
            return await GetAsync(id);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Approve)]
        public async Task<BomMasterDto> ApproveAsync(Guid id)
        {
            await BomMasterManager.ChangeStatus(id, DocumentStatus.Approved);
            return await GetAsync(id);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.UnApprove)]
        public async Task<BomMasterDto> UnApproveAsync(Guid id)
        {
            await BomMasterManager.ChangeStatus(id, DocumentStatus.Open);
            return await GetAsync(id);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Delete)]
        public async Task DeleteAsync(Guid id)
        {
            await BomMasterManager.DeleteAsync(id);
        }

        [Authorize(BasicArchivesPermissions.BomMaster.Query)]
        public async Task<List<BomComponentDto>> GetLeafChildrenAsync(Guid itemMasterId)
        {
            var parent = await BomMasterRepository.FindAsync(x => x.ItemMasterId == itemMasterId);
            if (parent == null) return null;

            var list = await BomMasterRepository.GetChildrenPagedListAsync(x => x.DocumentId == parent.Id, 0, int.MaxValue, null, true);
            if (list == null || list.Count <= 0) return null;

            var result = new List<BomComponentDto>();
            foreach (var component in list)
            {
                var componentChildren = await GetLeafChildrenAsync(component.ItemMasterId);
                if (componentChildren == null || componentChildren.Count <= 0)
                {
                    result.Add(ObjectMapper.Map<BomComponent, BomComponentDto>(component));
                }
                else
                {
                    result.AddRange(componentChildren);
                }
            }

            return result;
        }
    }
}